/*
 * @Author: c
 * @Date: 2024-02-06 10:39:42
 * @LastEditTime: 2024-03-27 17:40:35
 * @LastEditors: c
 * @Description: 
 * @FilePath: \music-web-backend\src\core\music\album\dao\album.dao.ts
 * https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
// Copyright 2024 Administrator
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { MinioClientService } from "src/core/system/minio/minio.service";
import { DataSource, Repository } from "typeorm";
import { FavoriteForm } from "../dto/create-album.dto";
import { AlbumPageQuery } from "../dto/search-album.dto";
import { Album } from "../entities/album.entity";
import { IAlbum } from "../interface/album.interface";

@Injectable()
export class DAlbum implements IAlbum {


    constructor(
        @InjectRepository(Album) private albumRepository: Repository<Album>,
        private dataSource: DataSource,
        private minioClientService: MinioClientService,
    ) { }

    /**
 * 歌手-歌手所有专辑
 * @param pageDto 
 * @returns 
 */
    async getArtistAlbumList(username: string, { alubmName, artistIds, pageNum = 1, pageSize = 100 }: AlbumPageQuery): Promise<[Album[], number]> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('album.genre', "genre")
            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                // 'song.duration',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',

                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ])
            .orderBy("album.createTime", 'ASC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)

        if (username) {
            build.leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            build.leftJoinAndSelect("song.paidUsers", "paid_user", "paid_user.username = :useranme")
            build.addSelect([
                'favor_user.id',
                'favor_user.username',
                'paid_user.id',
                'paid_user.username',
            ])
            build.setParameter('useranme', username)
        }

        if (alubmName) {
            build.where('album.title like :keywords', { keywords: `%${alubmName}%` });
        }

        if (artistIds && artistIds.length > 0) {
            build.andWhere('artist.id IN (:...artistIds)', { artistIds });
        }

        const [data, total] = await build.getManyAndCount();

        return [data, total]
    }

    /**
         * 专辑-新增-我收藏的歌曲
         * @param songForm 
         * @returns 
         */
    async createFavorite(userId: number, { id }: FavoriteForm): Promise<void> {
        //插入favor_user_song表的数据
        await this.albumRepository
            .createQueryBuilder('album')
            .relation(Album, 'favoriteUsers')
            .of(id)
            .add(userId)//多对多关系 新增与收藏者的关系
    }


    /**
    * 专辑-删除-我收藏的歌曲
    * @param songForm 
    * @returns 
    */
    async deleteFavorite(userId: number, { id }: FavoriteForm): Promise<void> {
        await this.albumRepository
            .createQueryBuilder('album')
            .relation(Album, 'favoriteUsers')
            .of(id)
            .remove(userId)//多对多关系 删除与收藏者的关系
    }

    /**
    * 专辑-删除-我收藏的歌曲
    * @param songForm 
    * @returns 
    */
    async myfavorite(userId: number, { pageNum, pageSize, alubmName }: AlbumPageQuery): Promise<[Array<Album>, number]> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('album.genre', "genre")
            .leftJoinAndSelect("album.favoriteUsers", "favor_user")
            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                // 'song.duration',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',

                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ])
            .orderBy("album.createTime", 'ASC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)

        if (userId) {
            build.where('favor_user.id = :userId', { userId });
        }

        if (alubmName) {
            build.andWhere('album.title like :keywords', { keywords: `%${alubmName}%` });
        }

        const [data, total] = await build.getManyAndCount();

        return [data, total]
    }

    /**
     * 专辑-下拉列表查询
     * @param pageNum 
     * @param pageSize 
     * @param alubmName 
     */
    async listOptions(pageNum: number, pageSize: number, alubmName: string): Promise<Album[]> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .select([
                'album.id',
                'album.title',
            ])
            .orderBy("album.createTime", 'DESC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)



        if (alubmName) {
            build.where('album.title like :keywords', { keywords: `%${alubmName}%` });
        }

        const data = await build.getMany();

        return data
    }
    /**
     * 专辑-单条数据查询
     * @param id 专辑id
     */
    async getOneById(id: number): Promise<Album> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('album.genre', "genre")
            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',
                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ]).where("album.id = :id", { id })


        const data = await build.getOne();

        return data
    }

    /**
     * 专辑-单条数据查询
     * @param id 专辑id
     * @param username 当前登录用户名
     * @returns 
     */
    async getOneByIdAndUsername(id: number, username: string): Promise<Album> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect("song.artistList", "song_artist")
            // .leftJoinAndSelect("song.paidUsers", "paid_user", "paid_user.username = :useranme")
            // .leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            .leftJoinAndSelect('album.genre', "genre")
            // .setParameter('useranme', username)
            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song_artist.id',
                'song_artist.name',
                'song.id',
                'song.title',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',
                // 'favor_user.id',
                // 'favor_user.username',
                // 'paid_user.id',
                // 'paid_user.username',
                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ]).where("album.id = :id", { id })

        if (username) {
            build.leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            build.leftJoinAndSelect("song.paidUsers", "paid_user", "paid_user.username = :useranme")
            build.leftJoinAndSelect("song.favoriteUsers", "song_favor_user", "song_favor_user.username = :useranme")
            build.addSelect([
                'favor_user.id',
                'favor_user.username',
                'paid_user.id',
                'paid_user.username',
                'song_favor_user.id',
                'song_favor_user.username',
            ])
            build.setParameter('useranme', username)
        }
        const data = await build.getOne();

        return data
    }


    async page(username: string, { pageNum, pageSize, alubmName,keywords }: AlbumPageQuery): Promise<[Album[], number]> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('album.genre', "genre")
            // .leftJoinAndSelect("song.paidUsers", "paid_user", "paid_user.username = :useranme")
            // .leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            // .setParameter('useranme', username)
            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                // 'song.duration',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',

                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ])
            .orderBy("album.createTime", 'ASC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)

        if (username) {
            build.leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            build.leftJoinAndSelect("song.paidUsers", "paid_user", "paid_user.username = :useranme")
            build.addSelect([
                'favor_user.id',
                'favor_user.username',
                'paid_user.id',
                'paid_user.username',
            ])
            build.setParameter('useranme', username)
        }

        if (alubmName) {
            build.where('album.title like :keywords', { keywords: `%${alubmName}%` });
        }

        if (keywords) {
            //mysql分词查询
            /**
             * 查看分词长度 SHOW VARIABLES LIKE ‘ngram_token_size’;
                修改分词长度 在MySQL的配置文件中(.ini)找到[mysqld]字样的地方，在下方添加ngram_token_size=1即可修改为支持1个字符起搜索（范围1~10）
             */
            build.where('MATCH(title,introduce) against(:keywords)', { keywords });
            // where MATCH(title,introduce) against('大飒')
        }

        const [data, total] = await build.getManyAndCount();

        return [data, total]
    }

    async xdpublish(username: string, pageNum: number, pageSize: number): Promise<[Album[], number]> {
        const build = await this.albumRepository
            .createQueryBuilder("album")
            .leftJoinAndSelect("album.artistList", "artist")
            .leftJoinAndSelect("album.pic", "file_info_pic")
            .leftJoinAndSelect("album.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('album.genre', "genre")


            .select([
                'album.id',
                'album.title',
                'album.lang',
                'album.releaseDate',
                'album.pushTime',
                'album.downTime',
                'album.payModel',
                'album.createTime',
                'album.isActive',
                'album.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',

                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ])
            .orderBy("album.createTime", 'ASC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)

        if (username) {
            build.leftJoinAndSelect("album.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            build.addSelect([
                'favor_user.id',
                'favor_user.username'
            ])
            build.setParameter('useranme', username)
        }

        const [data, total] = await build.getManyAndCount();

        return [data, total]
    }
}